package ua.kpi.ipsa.expert.api.net;

import java.rmi.*;
import java.rmi.server.*;
import java.util.*;

import ua.kpi.ipsa.expert.api.algorithm.*;
import ua.kpi.ipsa.expert.api.db.*;
import ua.kpi.ipsa.expert.api.server.*;

/**
 * 
 * @author doctorpro
 * 
 *         UserConsoleManager gives to all users GodConsoles without watching
 *         their rights
 * 
 */
public class UserConsoleManager implements ServerGateway, ConsoleReleaser {

	public static final String ADMIN_NAME = "admin";

	//
	DAO dao;

	//
	private final Map<String, DefaultUsersConsole> activeUsers = new HashMap<String, DefaultUsersConsole>();

	//
	private UserListener userRetranslator;

	//
	AlgoRunManager algoRunManager;
	CodePresentationManager presentationManager;

	// the one and only admin console
	private DefaultAdminsConsole adminConsole;
	private AdminsConsole adminConsoleStub;

	/**
	 * 
	 * @param userListener
	 */
	public UserConsoleManager(UserActionRetranslator userRetranslator, DAO dao,
			AlgoRunManager algoRunManager,
			CodePresentationManager presentationManager,
			LifecycleManager lifeManager) {

		this.dao = dao;
		this.algoRunManager = algoRunManager;
		this.presentationManager = presentationManager;

		//
		if (userRetranslator == null) {
			throw new NullPointerException(
					"UserActionRetranslator instance can't be null");
		}
		this.userRetranslator = userRetranslator;

		//
		adminConsole = new DefaultAdminsConsole(this, lifeManager, dao);
		try {
			// Registry r = LocateRegistry
			// .getRegistry(ServerMain.REMOTE_GATEWAY_NAME);
			adminConsoleStub = (AdminsConsole) UnicastRemoteObject
					.exportObject(adminConsole, 0);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		userRetranslator.addListener(adminConsole.getUserListener());

		//
		System.out.println("Starting users supervisor thread ...");
		Thread usersSupervisor = new UsersSupervisor(activeUsers, this);
		usersSupervisor.start();
	}

	/**
	 * 
	 */
	@Override
	public UsersConsole createUsersConsole(String login, String password,
			ServerToUserLeash l) throws RemoteException, ConsoleException {

		DefaultUsersConsole newConsole;

		//
		if (verifyUser(login, password)) {

			synchronized (activeUsers) {

				// check if user is already in system
				if (activeUsers.containsKey(login)) {
					throw new ConsoleException("User already logged in system");
				}

				// create new console
				newConsole = new DefaultUsersConsole(this, userRetranslator,
						login, l);

				//
				activeUsers.put(login, newConsole);
				userRetranslator.userLoggedIn(login);
			}

			//
			UsersConsole consoleStub = (UsersConsole) UnicastRemoteObject
					.exportObject(newConsole, 0);

			return consoleStub;
		} else {
			throw new ConsoleException("Wrong login or password given");
		}
	}

	/**
	 * 
	 * @param userToRelease
	 */
	@Override
	public void releaseUser(String userToRelease) {

		DefaultUsersConsole console;

		synchronized (activeUsers) {
			console = activeUsers.get(userToRelease);

			if (console != null) {
				console.setEnabled(false);
				activeUsers.remove(userToRelease);
				userRetranslator.userLoggedOut(userToRelease);
			}
		}
	}

	/**
	 * 
	 */
	@Override
	public void releaseConsole(DefaultUsersConsole console) {
		synchronized (activeUsers) {

			String userToRelease = console.getLogin();

			if (console != null) {
				activeUsers.remove(userToRelease);
				userRetranslator.userLoggedOut(userToRelease);
			}
		}
	}

	/**
	 * 
	 * @param login
	 * @param password
	 * @return
	 */
	private boolean verifyUser(String login, String password)
			throws ConsoleException {

		try {
			String realPassword = dao.getUserPassword(login);
			if (realPassword == null) {
				throw new ConsoleException("Incorrect login.");
			} else if (!realPassword.equals(password)) {
				throw new ConsoleException("Incorrect password.");
			}
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		}

		return true;
	}

	/**
	 * 
	 * @param password
	 * @return
	 */
	private boolean verifyAdmin(String password) {

		try {
			if (dao.getUserPassword(ADMIN_NAME) != null) {
				return dao.getUserPassword(ADMIN_NAME).equals(password);
			} else {
				System.out.println("Admin undefined");
				return false;
			}
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public AdminsConsole createAdminsConsole(String password)
			throws RemoteException, ConsoleException {

		if (adminConsoleStub == null) {
			throw new IllegalStateException("Admin console stub must be inited");
		}

		if (verifyAdmin(password)) {
			return adminConsoleStub;
		} else {
			throw new ConsoleException("Incorrect admin password");
		}
	}

	@Override
	public boolean assertOnline() throws RemoteException {
		return true;
	}
}